package JET;

import JET.editor.SelectionGroup;
import JET.geom.Rect2d;
import JET.geom.Vec2d;
import JET.physics.*;
import JET.physics.bodies.RigidBody;
import JET.physics.bodies.SpringBody;
import JET.physics.engine.JETContextHelper;
import java.util.ArrayList;
import java.util.Collection;

/**
 *
 * @author raos
 */
public class SceneHelper {

    public static ArrayList<Mass> getSpringBodyMassInRect2dList(Scene scene, Rect2d rect2d) {
        ArrayList<Mass> list = new ArrayList<Mass>();
        list.addAll(JETContextHelper.getSpringBodyMassInRect2dList(scene.getJETContext(), rect2d));

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol)
                list.addAll(JETContextHelper.getSpringBodyMassInRect2dList(si.getEngine(), rect2d));
        }
        
        return list;
    }

    public static Spring getSpringBodySpringAtPos(Scene scene, Vec2d vec, double catchAreaScale) {
        Spring spring = JETContextHelper.getSpringBodySpringAtPos(scene.getJETContext(), vec, catchAreaScale);
        if (spring!=null) return spring;

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                spring = JETContextHelper.getSpringBodySpringAtPos(si.getEngine(), vec, catchAreaScale);
                if (spring!=null) return spring;
            }
        }

        return null;
    }
    
    public static RSpring getSpringBodyRSpringAtPos(Scene scene, Vec2d vec, double catchAreaScale) {
        RSpring rSpring = JETContextHelper.getSpringBodyRSpringAtPos(scene.getJETContext(), vec, catchAreaScale);
        if (rSpring!=null) return rSpring;

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                rSpring = JETContextHelper.getSpringBodyRSpringAtPos(si.getEngine(), vec, catchAreaScale);
                if (rSpring!=null) return rSpring;
            }
        }

        return null;
    }

    public static Wall getSpringBodyWallAtPos(Scene scene, Vec2d vec, double catchAreaScale) {
        Wall wall = JETContextHelper.getSpringBodyWallAtPos(scene.getJETContext(), vec, catchAreaScale);
        if (wall!=null) return wall;

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                wall = JETContextHelper.getSpringBodyWallAtPos(si.getEngine(), vec, catchAreaScale);
                if (wall!=null) return wall;
            }
        }

        return null;
    }

    public static Mass getSpringBodyMassInRect2d(Scene scene, Rect2d rect2d) {
        Mass mass = JETContextHelper.getSpringBodyMassInRect2d(scene.getJETContext(), rect2d);
        if (mass!=null) return mass;

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                mass = JETContextHelper.getSpringBodyMassInRect2d(si.getEngine(), rect2d);
                if (mass!=null) return mass;
            }
        }

        return null;
    }
    public static Mass getSpringBodyMassClosestToVec2d(Scene scene, Vec2d v, boolean moveable) {
        Mass mass = JETContextHelper.getSpringBodyMassClosestToVec2d(scene.getJETContext(), v, moveable);
        if(mass!=null) return mass;

        double minDistSquared = Double.MAX_VALUE;
        Mass closestMass = null;

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                mass = JETContextHelper.getSpringBodyMassClosestToVec2d(si.getEngine(), v, moveable);
                if(mass!=null) return mass;
            }
        }

        return closestMass;
    }
    public static ArrayList<Mass> getSpringBodyMassesClosestToVec2d(Scene scene, Vec2d v, int count) {
        ArrayList list = new ArrayList(count);

        list.addAll(JETContextHelper.getSpringBodyMassesClosestToVec2d(scene.getJETContext(), v, count));

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol)
                list.addAll(JETContextHelper.getSpringBodyMassesClosestToVec2d(si.getEngine(), v, count));
        }

        return list;
    }

    public static SpringBody getSpringBodyThatOwnMass(Scene scene, Mass mass) {
        SpringBody sb = JETContextHelper.getSpringBodyThatOwnMass(scene.getJETContext(), mass);
        if (sb!=null) return sb;

        sb = JETContextHelper.getSpringBodyThatOwnMass(scene.getJETContext(), mass);

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                sb = JETContextHelper.getSpringBodyThatOwnMass(si.getEngine(), mass);
                if (sb!=null) return sb;
            }
        }

        return null;
    }
    public static SpringBody getSpringBodyThatOwnWall(Scene scene, Wall wall) {
        SpringBody sb = JETContextHelper.getSpringBodyThatOwnWall(scene.getJETContext(), wall);
        if (sb!=null) return sb;

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                sb = JETContextHelper.getSpringBodyThatOwnWall(si.getEngine(), wall);
                if (sb!=null) return sb;
            }
        }

        return null;
    }
    public static SpringBody getSpringBodyThatOwnSpring(Scene scene, Spring spring) {
        SpringBody sb = JETContextHelper.getSpringBodyThatOwnSpring(scene.getJETContext(), spring);
        if (sb!=null) return sb;

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                sb = JETContextHelper.getSpringBodyThatOwnSpring(si.getEngine(), spring);
                if (sb!=null) return sb;
            }
        }

        return null;
    }
    public static SpringBody getSpringBodyThatOwnRSpring(Scene scene, RSpring rSpring) {
        SpringBody sb = JETContextHelper.getSpringBodyThatOwnRSpring(scene.getJETContext(), rSpring);
        if (sb!=null) return sb;

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                sb = JETContextHelper.getSpringBodyThatOwnRSpring(scene.getJETContext(), rSpring);
                if (sb!=null) return sb;
            }
        }

        return null;
    }

    public static SceneItem getSceneItemThatOwnSpring(Scene scene, Spring spring) {
        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                if (si.getEngine().getSpringList().contains(spring))
                    return si;
            }
        }
        return null;
    }

    public static SceneItem getSceneItemThatOwnRSpring(Scene scene, RSpring rSpring) {
        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                if (si.getEngine().getRSpringList().contains(rSpring))
                    return si;
            }
        }
        return null;
    }

    public static SceneItem getSceneItemThatOwnSpringBody(Scene scene, SpringBody sb) {
        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                if (si.getEngine().getSpringBodyList().contains(sb))
                    return si;
            }
        }
        return null;
    }

    public static ArrayList<Spring> getSpringListOfMass(Scene scene, Mass mass, boolean fromEngine, boolean fromSpringBody, boolean fromSceneItems) {
        ArrayList<Spring> springs = new ArrayList<Spring>();

        springs.addAll(JETContextHelper.getSpringListOfMass(scene.getJETContext(), mass, fromEngine, fromSpringBody));

        if (fromSceneItems) {
            Collection<SceneItem> siCol = scene.getSceneItemsListSync();
            synchronized(siCol) {
                for(SceneItem si : siCol)
                    springs.addAll(JETContextHelper.getSpringListOfMass(si.getEngine(), mass, fromSceneItems, fromSpringBody));
            }
        }

        return springs;
    }

    public static ArrayList<RSpring> getRSpringListOfMass(Scene scene, Mass mass, boolean fromEngine, boolean fromSpringBodies, boolean fromSceneItems) {
        ArrayList<RSpring> rSprings = new ArrayList<RSpring>();

        rSprings.addAll(JETContextHelper.getRSpringListOfMass(scene.getJETContext(), mass, fromEngine, fromSpringBodies));

        if (fromSceneItems) {
            Collection<SceneItem> siCol = scene.getSceneItemsListSync();
            synchronized(siCol) {
                for(SceneItem si : siCol)
                    rSprings.addAll(JETContextHelper.getRSpringListOfMass(si.getEngine(), mass, fromSceneItems, fromSpringBodies));
            }
        }

        return rSprings;
    }
    public static ArrayList<Wall> getWallListOfMass(Scene scene, Mass mass) {
        ArrayList<Wall> walls = new ArrayList<Wall>();

        walls.addAll(JETContextHelper.getWallListOfMass(scene.getJETContext(), mass));

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol)
                walls.addAll(JETContextHelper.getWallListOfMass(si.getEngine(), mass));
        }

        return walls;
    }

    public static SelectionGroup getItemsInRect(Scene scene, Rect2d rect)
    {
        // TODO : lista ma zawierac wszyzstkie obiekty w graphic panelu aktualnie wskazywane przez mPos...

        SelectionGroup group = new SelectionGroup(scene);

        group.addMasses( SceneHelper.getMassesInRect(scene, rect) );
        group.addSprings( SceneHelper.getSpringsInRect(scene, rect) );
        group.addRSprings( SceneHelper.getRSpringsInRect(scene, rect) );
        group.addWalls( SceneHelper.getWallsInRect(scene, rect) );

        return group;
    }

    public static Object getItemClosestToVec2d(Scene scene, Vec2d v)
    {
        Object item = JETContextHelper.getItemClosestToVec2d(scene.getJETContext(), v);
        if (item!=null) return item;

        return null;
    }


    /**
     *
     * @param mPos position at wchich we look for spring body correpsonding to engine system
     * @return spring body at mPos position
     */
    public static SpringBody getSpringBodyAt(Scene scene, Vec2d mPos) {
        SpringBody sb = JETContextHelper.getSpringBodyAt(scene.getJETContext(), mPos);
        if (sb!=null) return sb;

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol) {
                sb = JETContextHelper.getSpringBodyAt(si.getEngine(), mPos);
                if (sb!=null) return sb;
            }
        }

        return null;
    }

    public static ArrayList<Mass> getMassesInRect(Scene scene, Rect2d rect) {
        ArrayList<Mass> list = new ArrayList<Mass>();

        list.addAll(JETContextHelper.getMassesInRect(scene.getJETContext(), rect));

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol)
                list.addAll(JETContextHelper.getMassesInRect(si.getEngine(), rect));
        }

        return list;
    }

    public static ArrayList<Spring> getSpringsInRect(Scene scene, Rect2d rect) {
        ArrayList<Spring> list = new ArrayList<Spring>();

        list.addAll(JETContextHelper.getSpringsInRect(scene.getJETContext(), rect));

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol)
                list.addAll(JETContextHelper.getSpringsInRect(si.getEngine(), rect));
        }

        return list;
    }

    public static ArrayList<RSpring> getRSpringsInRect(Scene scene, Rect2d rect) {
        ArrayList<RSpring> list = new ArrayList<RSpring>();

        list.addAll(JETContextHelper.getRSpringsInRect(scene.getJETContext(), rect));

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol)
                list.addAll(JETContextHelper.getRSpringsInRect(si.getEngine(), rect));
        }

        return list;
    }

    public static ArrayList<Wall> getWallsInRect(Scene scene, Rect2d rect) {
        ArrayList<Wall> list = new ArrayList<Wall>();

        list.addAll(JETContextHelper.getWallsInRect(scene.getJETContext(), rect));

        Collection<SceneItem> siCol = scene.getSceneItemsListSync();
        synchronized(siCol) {
            for(SceneItem si : siCol)
                list.addAll(JETContextHelper.getWallsInRect(si.getEngine(), rect));
        }

        return list;
    }

    public static RigidBody getRigidBodyAt(Scene scene, Vec2d pos) {
        RigidBody rb = JETContextHelper.getRigidBodyAt(scene.getJETContext(), pos);
        if (rb!=null) return rb;
        
        return null;
    }

    /**
     * Tests if specified rect contains any scene item.
     * @param scene Scene on which we test
     * @param rect Rectangle that is items catch area
     * @return True if there are any scene items withing bounds of rect, false otherwise.
     */
    public static boolean isMouseOverAnything(Scene scene, Rect2d rect)
    {
        return !getItemsInRect(scene, rect).isEmpty();
    }
}
